//
// libLoader.cpp for libLoader in /home/taitai/rtype/serveur
// 
// Made by yannis berrouag
// Login   <berrou_y@epitech.net>
// 
// Started on  Sat Jan  7 17:37:23 2012 yannis berrouag
// Last update Wed Jan 11 16:44:49 2012 yannis berrouag
//

#include "libLoader.hh"


std::map<std::string, maker_monster, std::less<std::string> > factory;

libLoader::libLoader() {
  loaded.clear();
  this->checkDir();
}


libLoader::libLoader(std::string path) {
  loaded.clear();
  this->checkDir(path);
}


libLoader::~libLoader() {
  std::map<std::string, void *>::iterator	it;
  for (it = this->loaded.begin(); it != this->loaded.end(); ++it)
    {
      dlclose((*it).second);
    }
  loaded.clear();
}

void	libLoader::checkDir(std::string dir)
{
  DIR	*opened;
  struct dirent	*r;
  
  if (dir[dir.size() - 1] != '/')
    dir += "/";
  opened = opendir(dir.c_str());
  if (opened == 0)
    {
      std::cerr << strerror(errno) << std::endl;
      return ;
    }
  while ((r = readdir(opened))) {
    if (this->isLib(r->d_name))
      {
	if (!this->isAlreadyLoaded(dir + r->d_name))
	  {
	    std::string libName = dir + r->d_name;
	    this->load(libName);
	  }
      }

  }
  closedir(opened);
}

bool	libLoader::isAlreadyLoaded(std::string lib)
{
  std::map<std::string, void *>::iterator it = loaded.find(getLibRealName(lib));
  if (it != loaded.end())
    return true;
  return false;
}

void	libLoader::load(std::string lib)
{
  void	*hndl;

  std::cout << "loading " << lib << std::endl;
  hndl = dlopen(lib.c_str(), RTLD_LAZY);
  if (hndl == NULL)
    {
      std::cerr << "dlopen : "<< dlerror() << std::endl;
      exit(1);
    }
  std::string realName = getLibRealName(lib);
  this->loaded[realName] = hndl;
}

std::string	libLoader::getLibRealName(std::string lib)
{
  std::string	name;
  int	i;
  
  i = lib.find_last_of("/");
  name = lib.substr(i, lib.size() - 1);
  name = name.substr(0, name.size() - 3);
  std::string	tmp = name;
  if (name.size() > 3 && name.substr(0, 3) == "lib")
    tmp = tmp.substr(3, name.size() - 1);
  return tmp;
}

bool	libLoader::isLib(std::string lib)
{
  std::string	toto;

  if (lib.size() < 4)
    return false;
  toto = lib.substr(lib.size() - 3 , lib.size() - 1);
  if (toto == ".so")
    return true;
  return false;
}

void	*libLoader::getMakerFromLib(std::string lib)
{
  std::map<std::string, void *>::iterator it = loaded.find(getLibRealName(lib));
  if (it != this->loaded.end())
    return (*it).second;
  return NULL;
}

monster *libLoader::getInstance(std::string name)
{
  std::map<std::string, maker_monster, std::less<std::string> >::iterator it;
  std::cout<< factory.size() << std::endl;
  for (it = factory.begin(); it != factory.end(); ++it)
    {
      std::cout << (*it).first << std::endl;
    }
  return factory[name]();
}

int	main(int ac, char **av)
{
  libLoader	l;
  
  monster	*alien = l.getInstance("Alien");
  alien->hello();
}
